package com.lyd.sweet.web.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyd.sweet.model.ResponseObject;
import com.lyd.sweet.web.annotation.SweetResponseHandler;
import com.lyd.sweet.web.properties.SweetHandlerProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.ArrayList;

/**
 * 针对RestController的统一返回值包装。
 * 引用微服务在controller中都直接返回原始结果，由该类统一包装成ResultObject对象返回。
 * 确保所有api返回格式一致。
 *
 * @author 木木
 **/
@RestControllerAdvice(basePackages = "com")
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {

    private static Logger logger = LoggerFactory.getLogger(ResponseResultHandler.class);

    /**
     * Handler配置
     */
    private final SweetHandlerProperties handlerProperties;

    public ResponseResultHandler(SweetHandlerProperties handlerProperties) {
        this.handlerProperties = handlerProperties;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        //如果RestController的返回值已经是ResponseObject则不处理。
        return !methodParameter.getGenericParameterType().equals(ResponseObject.class);
    }

    /**
     * 重写结构体输出写处理
     *
     * @param o
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

        String feignHeader = serverHttpRequest.getHeaders().getOrDefault("FEIGN-HEADER", new ArrayList<>(0)).toString();
        boolean isSweetFeignReq = feignHeader.contains("SweetFeign");
        boolean isResponseObject = o instanceof ResponseObject;
        if (isSweetFeignReq) {
            serverHttpResponse.getHeaders().set("IsResponseObject", isResponseObject + "");
            return o;
        }

        Object reObj = this.bodyWrite(o, methodParameter);
        if (methodParameter.getGenericParameterType().equals(String.class)) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                //返回值为String时Content-Type为text/html。这里强制转为application/json, 编码为UTF-8
                if (reObj instanceof String) {
                    return o;
                } else {
                    serverHttpResponse.getHeaders().set("Content-Type", "application/json;charset=UTF-8");
                    return objectMapper.writeValueAsString(ResponseObject.success(o));
                }
            } catch (Throwable e) {
                logger.warn("响应结果处理程序返回结果失败。返回值为：{}，error-msg：{}", o.toString(), e.getMessage());
                return o;
            }
        } else if (o instanceof InputStreamResource) {
            serverHttpResponse.getHeaders().set("IsResponseObject", "false");
            return o;
        }

        //非String对象的返回值，直接包装成ResultObject返回,如果是JSON，强制加上UTF-8编码
        if (mediaType.toString().equals(MediaType.APPLICATION_JSON_VALUE)) {
            serverHttpResponse.getHeaders().set("Content-Type", "application/json;charset=UTF-8");
        }

        return reObj;
    }

    /**
     * 输出具体的对象信息
     *
     * @param o
     * @param methodParameter
     * @return
     */
    public Object bodyWrite(Object o, MethodParameter methodParameter) {
        if (!this.isFormatRequest(methodParameter)) {
            return o;
        }

        if (o instanceof ResponseObject) {
            return o;
        }

        return ResponseObject.success(o);
    }

    /**
     * 判断是否包装
     *
     * @param methodParameter
     * @return true 要包装HEAD信息 false不需要包装
     */
    public boolean isFormatRequest(MethodParameter methodParameter) {
        boolean re = handlerProperties.isResultHandlerEnabled();
        // 处理类上注解
        SweetResponseHandler classAnnotation = methodParameter.getContainingClass().getAnnotation(SweetResponseHandler.class);
        SweetResponseHandler methodAnnotation = methodParameter.getMethodAnnotation(SweetResponseHandler.class);

        // 如果类上有注解，先按类处理
        if (!ObjectUtils.isEmpty(classAnnotation)) {
            re = classAnnotation.sFormat();
        }

        // 如果方法上有注解，按方法上处理
        if (!ObjectUtils.isEmpty(methodAnnotation)) {
            re = methodAnnotation.sFormat();
        }

        return re;
    }
}
